/**
 * Copyright (C) @2014 Webank Group Holding Limited
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package cn.webank.framework.integration.dao.dialect;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

import cn.webank.framework.dto.PageInfo;

public class MySqlDialect implements Dialect {

	@Override
	public String getCountSql(String sql) {
		String countSelect = getLineSql(sql);
		int orderIndex = getLastOrderInsertPoint(countSelect);

		int formIndex = getAfterFormInsertPoint(countSelect);
		String select = countSelect.substring(0, formIndex);

		// 如果SELECT 中包含 DISTINCT 只能在外层包含COUNT
		if (select.toLowerCase().indexOf("select distinct") != -1
				|| countSelect.toLowerCase().indexOf("group by") != -1) {
			return new StringBuffer(countSelect.length())
					.append("select count(1) count from (")
					.append(countSelect.substring(0, orderIndex))
					.append(" ) t").toString();
		} else {
			return new StringBuffer(countSelect.length())
					.append("select count(1) count ")
					.append(countSelect.substring(formIndex, orderIndex))
					.toString();
		}
	}

	/**
	 * 得到最后一个Order By的插入点位置
	 * 
	 * @return 返回最后一个Order By插入点的位置
	 */
	private static int getLastOrderInsertPoint(String querySelect) {
		int orderIndex = querySelect.toLowerCase().lastIndexOf("order by");
		if (orderIndex == -1
				|| !isBracketCanPartnership(querySelect.substring(orderIndex,
						querySelect.length()))) {
			throw new RuntimeException("My SQL 分页必须要有Order by 语句!");
		}
		return orderIndex;
	}

	/**
	 * 得到分页的SQL
	 * 
	 * @param sql
	 *            sql脚本
	 * @param pageInfo
	 *            分页对象
	 * @return 分页SQL
	 */
	@Override
	public String getLimitSql(String sql, PageInfo pageInfo) {
		int offset = (pageInfo.getCurrentPage() - 1) * pageInfo.getPageSize();
		int limit = pageInfo.getPageSize();
		String querySelect = getLineSql(sql);

		// querySelect = querySelect.replaceAll("[^\\s,]+\\.", "") + " limit "
		// + offset + " ," + limit;

		return querySelect + " limit " + offset + " ," + limit;

	}

	/**
	 * 将SQL语句变成一条语句，并且每个单词的间隔都是1个空格
	 * 
	 * @param sql
	 *            SQL语句
	 * @return 如果sql是NULL返回空，否则返回转化后的SQL
	 */
	private static String getLineSql(String sql) {
		return sql.replaceAll("[\r\n]", " ").replaceAll("\\s{2,}", " ");
	}

	/**
	 * 得到SQL第一个正确的FROM的的插入点
	 */
	private static int getAfterFormInsertPoint(String querySelect) {
		String regex = "\\s+FROM\\s+";
		Pattern pattern = Pattern.compile(regex, Pattern.CASE_INSENSITIVE);
		Matcher matcher = pattern.matcher(querySelect);
		while (matcher.find()) {
			int fromStartIndex = matcher.start(0);
			String text = querySelect.substring(0, fromStartIndex);
			if (isBracketCanPartnership(text)) {
				return fromStartIndex;
			}
		}
		return 0;
	}

	/**
	 * 判断括号"()"是否匹配,并不会判断排列顺序是否正确
	 * 
	 * @param text
	 *            要判断的文本
	 * @return 如果匹配返回TRUE,否则返回FALSE
	 */
	private static boolean isBracketCanPartnership(String text) {
		if (text == null
				|| (getIndexOfCount(text, '(') != getIndexOfCount(text, ')'))) {
			return false;
		}
		return true;
	}

	/**
	 * 得到一个字符在另一个字符串中出现的次数
	 * 
	 * @param text
	 *            文本
	 * @param ch
	 *            字符
	 */
	private static int getIndexOfCount(String text, char ch) {
		int count = 0;
		for (int i = 0; i < text.length(); i++) {
			count = (text.charAt(i) == ch) ? count + 1 : count;
		}
		return count;
	}

}
